#pragma once

#include <ft2build.h>
#include FT_FREETYPE_H

#include "BltInfo.h"
#include "Font.h"
#include "MyD3D.h"
#include "Window.h"
#include "Graphic2D.h"

using namespace Graphics;

namespace Graphics
{
	class GraphicFactory;
}

namespace D3Ds
{
	class GraphicD3D:public Graphic2D
	{
		friend class GraphicFactoryD3D;

		// freetype support
		FT_Library		m_FT_library;
		FT_Face			m_FT_face;
		Font			m_Font;
		int				m_FontHeight;
		
		Rect				m_RenderRect;

		WinApp::Window&		m_Win;
		ID3DXSprite*		m_pSprite;
		LPDIRECT3DSURFACE9	m_pBackBuffer;
		LPDIRECT3DTEXTURE9	m_pD3DTexture;
		LPDIRECT3DDEVICE9	m_pD3DDevice;
		LPDIRECT3DTEXTURE9	m_pTempBuffer;

		// vertex buffer
		IDirect3DVertexBuffer9*	m_pVB;
		
		// pointer of vertex buffer
		RTG_VERTEX*				m_pVertex;
		
		// index buffer for render quad
		IDirect3DIndexBuffer9*	m_pIB;
		
		// vertex array for render quad
		RTG_VERTEX		m_Quad[4];
		
		// quad count of vertex buffer
		int m_PrimCount;

		// graphic state
		LPDIRECT3DTEXTURE9		m_pLastTexture;
		LPDIRECT3DSURFACE9		m_pLastTarget;
		bool					m_IsBegin;
		bool					m_IsUpdate;
		bool					m_IsDiffuseOnly;
		BLEND_TYPE				m_LastBlendType;
		
		bool Init();
		explicit GraphicD3D(WinApp::Window& win);

	public:
		// Set the font type
		bool SetFont(const Font& font);

		// render text to the render target
		bool RenderText(const std::wstring& text, const Rect& destRect);

		// draw text in the target rect
		virtual bool TextDraw(const std::wstring& text,
							  const Font& font,
							  const Rect& destRect);

		// render all the renderable object
		virtual bool RenderAll(void);

		// draw a 2D rect to the target
		virtual bool Blt(Drawable* pSrc,
						 const Rect* pSrcRect, 
						 const Rect* pDestRect,
						 const BltInfo* pBltInfo);
		
		// clear the screen
		virtual bool Clear(Rect* const pRect=0, DWORD color=0);

		// be called by clocksource
		void OnClock(SourceType& t);

		// transform the target
		bool Transform2D(	float ox,float oy,				// translation
							float cx,float cy,float angle,	// rotation
							float scaleX,float scaleY);		// scale

		// rotate the target
		bool Transform3D(	float ox,float oy,float oz,	// translation
							float cx,float cy,float cz,	// rotation
							float rx,float ry,float rz,float angle,
							float scaleX,float scaleY,float scaleZ);	// scale

		// change render target
		bool SetRenderTarget(LPDIRECT3DSURFACE9	pSurface);

		// render a quad
		bool RenderQuad(	LPDIRECT3DTEXTURE9 pTexture,
							const Rect& srcRect,
							const Rect& destRect,
							const BltInfo* pBltInfo);
		bool RenderQuad(	LPDIRECT3DTEXTURE9 pTexture,
							RTG_VERTEX* pVertex);

		// update the vertex buffer to target
		bool Update(bool isEnd = false);

		// called before renderquad
		bool Begin(void);

		// called after renderquad
		bool End(void);

		// refresh the screen
		bool Present(void);

		// clear the surface
		bool ClearSurface(	LPDIRECT3DSURFACE9 const pSurface, 
							Rect* const pRect=0,
							DWORD color=0);

		virtual bool BindTexture(void);
		bool BindTextureD3D( LPDIRECT3DTEXTURE9 pTexture);

		virtual void				SetRenderRect(const Rect& rect);
		virtual const Rect&			GetRenderRect(void);
		virtual	int					GetWidth(void);
		virtual	int					GetHeight(void);
		LPDIRECT3DDEVICE9			GetDevice(void);
		ID3DXSprite*				GetSprite(void);

	private:
		~GraphicD3D(void);
	};
}